#ifndef __LOGGER_H__
#define __LOGGER_H__

#include <libgen.h>

#ifdef __cplusplus
extern "C" {
#endif

enum {
    LOG_FATAL = 0,
    LOG_ERROR,
    LOG_WARN,
    LOG_INFO,
    LOG_DEBUG,
    LOG_VERBOSE,
};

void log_set_debug_level(int level);
void log_set_assert_hook(void (*hook)(const char* expr, const char* func, int line));
void log_debug(int level, const char *tag, const char *file, const char *func, \
               int line, const char *fmt, ...) __attribute__((format(printf, 6, 7)));

#define LOG_DEBUG(level, tag, ...)   \
            log_debug(level, tag, basename((char *)__FILE__), __func__, __LINE__, __VA_ARGS__)

#ifndef LOG_TAG
#define LOG_TAG ""
#endif

#ifndef LOG_OUTPUT
#define LOG_OUTPUT  stderr
#endif

#define LOG_BUF_SIZE    2048

#define LOG_F(...)      LOG_DEBUG(LOG_FATAL, LOG_TAG, __VA_ARGS__)
#define LOG_E(...)      LOG_DEBUG(LOG_ERROR, LOG_TAG, __VA_ARGS__)
#define LOG_W(...)      LOG_DEBUG(LOG_WARN, LOG_TAG, __VA_ARGS__)
#define LOG_I(...)      LOG_DEBUG(LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOG_D(...)      LOG_DEBUG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOG_V(...)      LOG_DEBUG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)

#define LOG_LVL(level)  log_set_debug_level(level)
#define LOG_HOOK(hook)  log_set_assert_hook(hook)

#ifdef LOG_ASSERT_ENABLE
    #define LOG_A(EXPR)                                                                         \
    if (!(EXPR)) {                                                                              \
        if (NULL == log_assert_hook) {                                                          \
            LOG_F("log" "(%s) has assert failed at %s:%d.", #EXPR, __FUNCTION__, __LINE__);     \
            while (1);                                                                          \
        } else {                                                                                \
            log_assert_hook(#EXPR, __FUNCTION__, __LINE__);                                     \
        }                                                                                       \
    }
#else
    #define LOG_A(EXPR)     ((void)0);
#endif
extern void (*log_assert_hook)(const char* expr, const char* func, int line);

#ifdef __cplusplus
}
#endif

#endif  /** !__LOGGER_H__ */
